package Engine;

import gra.Account;
import gra.Card;

/**
 * Klasa Silnika gry.
 * Zadania: zozpoznawanie konfiguracji,poszukiwanie zwyciescy.
 */
public class Engine2 
{
    /**
     * Pole zawierajace informacje o wszystkich graczach.
     */
    private Account[] gracze;
    
    /**
     * Konstruktor klasy Engine2.
     * 
     * @param in    Tablica zawierajaca konta graczy ktorzy maja uczestniczyc w grze.
     */
    public Engine2(Account[] in)//Konstruktor klasy.
    {
        gracze = in;
    }
    
    /**
     * Metoda obliczajaca zwyciezce (lub zwyciezcow w przypadku remisow).
     * 
     * @return  Tablica zawierajaca zwyciezcow danej rozgrywki.
     */
    public Account[] zwyciesca()
    {
        Account[] Wynik;
        
        for(Account gracz : gracze)
        {
            if(gracz.active)
                uklad(gracz);
        }
        
        Wynik = znajdz();
        return Wynik;
    }
    
    /**
     * Sprawdza jaki uklad posiada dany gracz.
     * 
     * @param gracz Gracz ktorego uklad chcemy sprawdzic.
     */
    private void uklad( Account gracz )
    {
        gracz.rank = 9;
        if ( para    ( gracz ) ) gracz.rank = 8;
        if ( dwiePary( gracz ) ) gracz.rank = 7;
        if ( trojka  ( gracz ) ) gracz.rank = 6;
        if ( strit   ( gracz ) ) gracz.rank = 5;
        if ( kolor   ( gracz ) ) gracz.rank = 4;
        if ( ful     ( gracz ) ) gracz.rank = 3;
        if ( czworka ( gracz ) ) gracz.rank = 2;
        if ( poker   ( gracz ) ) gracz.rank = 1;
    }
    
    /**
     * Metoda szukajaca zwyciezcy.
     * 
     * @return Tablica ze zwyciezca, badz zwyciezcami  przypadku remisu.
     */
    private Account[] znajdz()
    {
        Account[] temp = null;
        int NajlepszyUklad = 10;
        int rozmiar = 0, i = 0;  
        
        for( Account gracz : gracze )//Sprawdzenie najlepszego ukladu.
        {
            if( NajlepszyUklad > gracz.rank && gracz.active)
            {
                NajlepszyUklad = gracz.rank;
            }
        }
        
        for( Account gracz : gracze )//Szukanie graczy z najlepszym ukladem.Zliczanie ilosci graczy z tym samym ukladem.
        {
            if( NajlepszyUklad == gracz.rank && gracz.active)
            {
                rozmiar++;
            }
        }
        
        temp =  new Account[rozmiar];
        
        for( Account gracz : gracze )//Zapsisywanie do tablicy temp, graczy z najlepszym ukladem.
        {
            if( NajlepszyUklad == gracz.rank && gracz.active)
            {
                temp[i] = gracz;
                i++;
            }
        }
        
        if( rozmiar == 1 )//Gdy posiadamy jednego ostatecznego zwyciesce.
        {
            return temp;
        }
        
        temp = rozstrzygnij( temp );//Gdy posiadamy kilku graczy z tym samym ukladem.
        return temp;
    }
    
    /**
     * Metoda rozstrzygajaca remisy.
     * 
     * @param gracze    Tablica z kontami graczy ktorych chcemy porownac.
     * @return          Tablica.   
     */
    private Account[] rozstrzygnij( Account[] gracze )//Rozstrzyga remisy.
    {
        Account[] temp       = new Account[4];
        Account   najlepszy  = gracze[0];
        Account[] ostateczny = null;
        
        int i = 0;
        
        for( Account gracz : gracze )
        {
            int sprawdz = porownaj( gracz, najlepszy );
            if( sprawdz == 2 )
            {//Gracz jest lepszy od najlepszego.
                najlepszy = gracz;
                for( int j = 0; j < i; j++)
                {
                    temp[j] = null;
                }
                temp[0] = najlepszy;
                i = 0;
                i++;
            }
            
            if( sprawdz == 1 )//Remis
            {
                temp[i] = gracz;
                i++;
            }
        }
        
        ostateczny = new Account[i];
        for( int j = 0; j < i; j++ )
        {
            ostateczny[j] = temp[j];
        }
        
        return ostateczny;
    }
    
    /**
     * Metoda sprawdzajaca czy aktualnie rozpatrywany gracz jest lepszy od najlepszego.
     * 
     * @param gracz     Gracz ktorego aktualnie rozpatrujemy.
     * @param najlepszy Gracz ktory aktualnie jest najlepszy.
     * @return          Mozliwe zwracane wartosci to: 
     *                   0 - przegrana
     *                   1 - remis
     *                   2 - wygrana
     */
    private int porownaj( Account gracz, Account najlepszy )
    {
        switch( gracz.rank )
        {   
            //poker
            case 1 :
            {
                if( gracz.Mpoker >  najlepszy.Mpoker ) return 2;
                if( gracz.Mpoker == najlepszy.Mpoker ) return 1;

                break;
            }
            //kareta
            case 2 :
            {
                if( gracz.Mczworka >  najlepszy.Mczworka ) return 2;
                if( gracz.Mczworka == najlepszy.Mczworka ) return 1;

                break;
            }
            //full
            case 3 :
            {
                if( gracz.Mful >  najlepszy.Mful ) return 2;
                if( gracz.Mful == najlepszy.Mful ) return 1;

                break;
            }
            //kolor
            case 4 :
            {
                if( gracz.Mkolor >  najlepszy.Mkolor ) return 2;
                if( gracz.Mkolor == najlepszy.Mkolor )
                {
                    for( int i = 1; i < 5; i++ )//Zakladamy ze karty sa posortowane,rosnaca.
                    {
                        if( gracz.hand[i].value > najlepszy.hand[i].value ) return 2;
                        if( gracz.hand[i].value < najlepszy.hand[i].value ) return 0; 
                    }
                    return 1;
                }

                break;
            }
            //strit
            case 5 :
            {
                if( gracz.Mstrit >  najlepszy.Mstrit ) return 2;
                if( gracz.Mstrit == najlepszy.Mstrit ) return 1;

                break;
            }
            //trojka
            case 6 :
            {
                if( gracz.Mtrojka >  najlepszy.Mtrojka ) return 2;
                if( gracz.Mtrojka == najlepszy.Mtrojka ) return 1;
                
                break;
            }
            //dwie pary
            case 7 :
            {
                if( gracz.Mpara1 >  najlepszy.Mpara1 ) return 2;
                if( gracz.Mpara1 == najlepszy.Mpara1 )
                {
                    if( gracz.Mpara2 >  najlepszy.Mpara2 ) return 2;
                    if( gracz.Mpara2 == najlepszy.Mpara2 )
                    {
                        if( gracz.Kicker >  najlepszy.Kicker ) return 2;
                        if( gracz.Kicker == najlepszy.Kicker ) return 1;
                    }
                }
                break;
            }
            //jedna para
            case 8 :
            {
                if( gracz.Mpara1 >  najlepszy.Mpara1 ) return 2;
                if( gracz.Mpara1 == najlepszy.Mpara1 )
                {
                    for( int i = 0; i < 5; i++ )//Zakladamy ze karty sa posortowane,rosnaca.
                    {
                        if( gracz.hand[i].value != gracz.Mpara1 )
                        {
                            if( gracz.hand[i].value > najlepszy.hand[i].value ) return 2;
                            if( gracz.hand[i].value < najlepszy.hand[i].value ) return 0;
                        }
                    }
                    return 1;
                }
                break;
            }
            //najwyzsza karta
            case 9 :
            {
                if( gracz.najwyzsza > najlepszy.najwyzsza ) return 2;
                if( gracz.najwyzsza == najlepszy.najwyzsza )
                {
                    for( int i = 1; i < 5; i++ )//Zakladamy ze karty sa posortowane,rosnaca.
                    {
                        if( gracz.hand[i].value > najlepszy.hand[i].value ) return 2;
                        if( gracz.hand[i].value < najlepszy.hand[i].value ) return 0; 
                    }
                    return 1;
                }
                break;
            }

        }
        return 0;
    }
    
    /**
     * Metoda sortujaca karty w tablicy hand gracza gracz
     * 
     * @param gracz  Argument typu Account zawierajacy konto aktualnie rozpatrywanego gracza.
     */
    public void sortuj( Account gracz )//Sortuje karty w tablicy.
    {
        for( int m = 0; m < gracz.hand.length - 1 ; m++ ) 
        { 
            for( int n = 0; n < gracz.hand.length - 1; n++ ) 
            { 
                if( gracz.hand[n+1].value > gracz.hand[n].value ) 
                { 
                    Card Temp = gracz.hand[n]; 
                    gracz.hand[n] = gracz.hand[n+1] ; 
                    gracz.hand[n+1] = Temp; 
                } 
            } 
        } 
    }
    
    /**
     * Metoda sprawdzajaca czy gracz podany jako argument ma pokera.
     * 
     * @param gracz Konto gracza ktorego konfiguracje sprawdzamy.
     * @return      Zwraca 1 - gdy gracz ma ta konfiguracje, 0 - gdy nie ma.
     */
    public boolean poker( Account gracz )
    {
        sortuj( gracz );
        if( kolor( gracz ) && strit(gracz) )
        {
             gracz.Mpoker = gracz.hand[0].value;
             return true;
        }
        return false;
    }
    
    /**
     * Metoda sprawdzajaca czy gracz podany jako argument ma karete.
     * 
     * @param gracz Konto gracza ktorego konfiguracje sprawdzamy.
     * @return      Zwraca 1 - gdy gracz ma ta konfiguracje, 0 - gdy nie ma.
     */
    public boolean czworka( Account gracz )
    {
        sortuj( gracz );
        int wystapienie = 0;
        int powtorka = gracz.hand[0].value;
        
        for( Card karta : gracz.hand )
        {
            if( wystapienie == 4 )
            {
                gracz.Mczworka = powtorka;
                break;
            }
            if( karta.value == powtorka ) 
            {
                ++wystapienie;
            }
            else
            {
                powtorka    = karta.value;
                wystapienie = 1;
            }
        }
        
        
        
        if( wystapienie == 4 )
        {
            //gracz.Mczworka = powtorka;
            return true;
        }
        return false;
    }
    
    /**
     * Metoda sprawdzajaca czy gracz podany jako argument ma fulla.
     * 
     * @param gracz Konto gracza ktorego konfiguracje sprawdzamy.
     * @return      Zwraca 1 - gdy gracz ma ta konfiguracje, 0 - gdy nie ma.
     */
    public boolean ful( Account gracz )
    {
        sortuj( gracz );
        int wystapienie = 0;
        int Max         = 0;
        int powtorka    = gracz.hand[0].value;
        int wynik       = 0;
        int[] tab       = new int[2];
        int i           = 0;
        
        
        for( int j = 0; j < 2; j++ )
        {
            tab[j] = -1;
        }
        
        for( Card karta : gracz.hand )
        {
            if( wystapienie == 4 ) return false;
            if( wystapienie == 3 )
            {
                wynik = powtorka;
                Max++;
            }
            if( wystapienie == 2 )
            {
                tab[i] = powtorka;
                i++;
            }
            if( karta.value == powtorka ) ++wystapienie;
            else
            {
                powtorka    = karta.value;
                wystapienie = 1;
            }
        }
        
        if( wystapienie == 3 )
        {
            wynik = powtorka;
            Max++;
        }
        
        if( Max == 1 )
        {
            for( int j = 0; j < 2; j++ )
            {
                if( wystapienie == 2 )
                    break;
                if( wystapienie != 2 && tab[j] == -1 )
                {
                    return false;
                }
            }
            gracz.Mful = wynik;
            return true;
        }
        return false;
    }
    
    /**
     * Metoda sprawdzajaca czy gracz podany jako argument ma kolor.
     * 
     * @param gracz Konto gracza ktorego konfiguracje sprawdzamy.
     * @return      Zwraca 1 - gdy gracz ma ta konfiguracje, 0 - gdy nie ma.
     */
    public boolean kolor( Account gracz )
    {
        sortuj( gracz );
        int wystapienie = 0;
        int powtorka    = gracz.hand[0].colour;
        
        for( Card karta : gracz.hand )
        {
            if( wystapienie == 5 ) break;
            if( karta.colour == powtorka )
                ++wystapienie;
            else
            {
                powtorka    = karta.colour;
                wystapienie = 1;
            }
        }
        if( wystapienie == 5 )
        {
            gracz.Mkolor = gracz.hand[0].value;
            return true;
        }
        return false;
    }
    
    /**
     * Metoda sprawdzajaca czy gracz podany jako argument ma strita.
     * 
     * @param gracz Konto gracza ktorego konfiguracje sprawdzamy.
     * @return      Zwraca 1 - gdy gracz ma ta konfiguracje, 0 - gdy nie ma.
     */
    public boolean strit( Account gracz )
    {
        sortuj( gracz );
        int ostatni = 102;
        
        for( Card karta : gracz.hand )
        {
            if( ostatni == 102 )
                ostatni = karta.value;
            else
            {
                if( !( ostatni == karta.value+1 ) ) return false;
                
                ostatni = karta.value;
            }
        }
        gracz.Mstrit = gracz.hand[0].value;
        return true;
    }
    
    /**
     * Metoda sprawdzajaca czy gracz podany jako argument ma trojke.
     * 
     * @param gracz Konto gracza ktorego konfiguracje sprawdzamy.
     * @return      Zwraca 1 - gdy gracz ma ta konfiguracje, 0 - gdy nie ma.
     */
    public boolean trojka( Account gracz )
    {
        sortuj( gracz );
        int wystapienie = 0;
        int Max         = 0;
        int powtorka    = gracz.hand[0].value;
        int wynik       = 0;
        
        for( Card karta : gracz.hand )
        {
            if( wystapienie == 4 ) return false;
            
            if( wystapienie == 3 )
            {
                wynik = powtorka;
                Max++;
            }
            
            if( karta.value == powtorka ) ++wystapienie;
            else
            {
                powtorka    = karta.value;
                wystapienie = 1;
            }
        }
        if( wystapienie == 4 ) return false;
        
        if( wystapienie == 3 )
        {
            wynik = powtorka;
            Max++;
        }
        
        if( Max == 1 )
        {
            if( wystapienie == 2 ) return false;
            
            gracz.Mtrojka = wynik;
            return true;
        }
        return false;
    }
    
    /**
     * Metoda sprawdzajaca czy gracz podany jako argument ma dwie pary.
     * 
     * @param gracz Konto gracza ktorego konfiguracje sprawdzamy.
     * @return      Zwraca 1 - gdy gracz ma ta konfiguracje, 0 - gdy nie ma.
     */
    public boolean dwiePary( Account gracz )
    {
        sortuj( gracz );
        int wystapienie = 0;
        int Max         = 0;
        int powtorka    = gracz.hand[0].value;
        int wynik       = 0;
         
        for( Card karta : gracz.hand )
        {
            if( wystapienie == 4 ) return false;
            if( wystapienie == 3 ) return false; 
            if( wystapienie == 2 )
            {
                if( Max == 1 ) gracz.Mpara1 = powtorka;
                wynik = powtorka;
                Max++;
            }
            
            if( karta.value == powtorka ) ++wystapienie;
            else
            {
                powtorka    = karta.value;
                wystapienie = 1;
            }
        }
        
        if( wystapienie == 2 )
        {
            if( Max == 1 ) gracz.Mpara1 = powtorka;
            wynik = powtorka;
            Max++;
        }
        
        if( Max == 2 )
        {
            gracz.Mpara2 = wynik;
            
            for( Card karta : gracz.hand )
            {
                if( karta.value != gracz.Mpara2 && karta.value != gracz.Mpara1 )
                {
                    gracz.Kicker = karta.value;
                }
            }
            
            return true;
        }
        return false;
    }
    
    /**
     * Metoda sprawdzajaca czy gracz podany jako argument ma jedna pare.
     * 
     * @param gracz Konto gracza ktorego konfiguracje sprawdzamy.
     * @return      Zwraca 1 - gdy gracz ma ta konfiguracje, 0 - gdy nie ma.
     */
    public boolean para( Account gracz )
    {
        sortuj( gracz );
        int wystapienie = 0;
        int Max         = 0;
        int powtorka    = gracz.hand[0].value;
        int wynik       = 0;
        
        for( Card karta : gracz.hand )
        {
            if( wystapienie == 4 ) return false;
            if( wystapienie == 3 ) return false;
            if( wystapienie == 2 )
            {
                wynik = powtorka;
                Max++;
            }
            
            if( karta.value == powtorka ) ++wystapienie;
            else
            {
                powtorka    = karta.value;
                wystapienie = 1;
            }
        }

        if( wystapienie == 3 || wystapienie == 4 ) return false;

        if( wystapienie == 2 )
        {
            wynik = powtorka;
            Max++;
        }
        
        if( Max == 1 )
        {
            gracz.Mpara1 = wynik;
            return true;
        }
        
        return false;
    }
}
